package com.gmrz.uaf.protocol.v1.json;

import com.gmrz.uaf.common.Constants;
import com.gmrz.uaf.common.UAFRuntimeException;
import com.gmrz.uaf.protocol.v1.processor.exception.InvalidUAFMessageException;
import com.gmrz.uaf.protocol.v1.schema.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import java.security.cert.Certificate;
import java.util.List;

public class UAFSchemaBuilder {
	private static UAFSchemaBuilder INSTANCE = null;
	private static UAFSchemaBuilder CERT_INSTANCE = null;

	private GsonBuilder builder = null;

	private UAFSchemaBuilder() throws InvalidUAFMessageException {
		this.builder = getBuilder();
		// 针对特定的类定制序列化、反序列化，将其注册到Gson中，进行序列化、反序列化时就会自动调用
		this.builder.registerTypeAdapter(ASMRegResponse.class,
				new ASMRegResponseAdapter())
				.registerTypeAdapter(ASMSignResponse.class,
						new ASMSignResponseAdapter());
	}

	private UAFSchemaBuilder(String type) throws InvalidUAFMessageException {
		this.builder = getBuilder();
		this.builder.registerTypeAdapter(ASMRegResponse.class,
				new CertASMRegResponseAdapter())
				.registerTypeAdapter(ASMSignResponse.class,
						new CertASMSignResponseAdapter());
	}

	public static Gson getGson() {
		return INSTANCE.builder.create();
	}

	public static Gson getGsonProcessCert(){
		return CERT_INSTANCE.builder.create();
	}

	public static GsonBuilder getBuilder() throws InvalidUAFMessageException {
		TypeToken<List<RegistrationRequest>> listRegistrationRequests = new TypeToken<List<RegistrationRequest>>() {
		};
//		TypeToken<List<DeviceSupportResponse>> listDeviceSupportResponses = new TypeToken<List<DeviceSupportResponse>>() {
//		};
		TypeToken<List<RegistrationResponse>> listRegistrationResponses = new TypeToken<List<RegistrationResponse>>() {
		};
		TypeToken<List<AuthenticationAssertion>> listAuthenticationAssertions = new TypeToken<List<AuthenticationAssertion>>() {
		};
		TypeToken<List<RegistrationAssertion>> listRegistrationAssertions = new TypeToken<List<RegistrationAssertion>>() {
		};
		TypeToken<List<Authenticator>> listAuthenticators = new TypeToken<List<Authenticator>>() {
		};
		TypeToken<List<FacetID>> listFacets = new TypeToken<List<FacetID>>() {
		};
		TypeToken<List<Extension>> listExtensions = new TypeToken<List<Extension>>() {
		};
		TypeToken<List<Policy>> listPolicies = new TypeToken<List<Policy>>() {
		};
		TypeToken<List<MatchCriteria>> listCriteria = new TypeToken<List<MatchCriteria>>() {
		};
		TypeToken<List<WhiteList>> listWhiteList = new TypeToken<List<WhiteList>>(){
		};
		// TypeToken<List <RegContext>> listRegReqs = new TypeToken<List
		// <RegContext>>() {
		// };
		// TypeToken listAuthReqs = new TypeToken() {
		// };
		// TypeToken listDeregReqs = new TypeToken() {
		// };
		TypeToken<Base64URLEncoded> fcParams = new TypeToken<Base64URLEncoded>() {
		};
		TypeToken<Base64URLEncoded<List<PNGCharacteristics>>> b64PngInfo = new TypeToken<Base64URLEncoded<List<PNGCharacteristics>>>() {
		};
		TypeToken<List<AuthenticatorAttachment>> listAuthenticatorAttachment = new TypeToken<List<AuthenticatorAttachment>>() {
		};
		
		return new GsonBuilder()
				// excludeFieldsWithoutExposeAnnotation 是为了使 @Expose 注解生效，@Expose：表示此字段进行序列化与反序列化
				.excludeFieldsWithoutExposeAnnotation()
				.registerTypeAdapter(AAID.class, new AAIDAdapter())
//				.registerTypeAdapter(ASMRegResponse.class,
//						new ASMRegResponseAdapter())
//				.registerTypeAdapter(ASMSignResponse.class,
//						new ASMSignResponseAdapter())
				.registerTypeAdapter(ChannelID.class, new ChannelIDAdapter())
				.registerTypeAdapter(FacetID.class, new FacetIDAdapter())
				.registerTypeAdapter(KeyID.class, new KeyIDAdapter())
				.registerTypeAdapter(ListSupportedSchemes.class,
						new ListSupportedSchemesAdapter())
				.registerTypeAdapter(ListAttestationCerts.class,
						new ListAttestationCertsAdapter())
				.registerTypeAdapter(ServerChallenge.class,
						new ServerChallengeAdapter())
				.registerTypeAdapter(ServerData.class, new ServerDataAdapter())
				.registerTypeAdapter(SupportedScheme.class,
						new SupportedSchemeAdapter())
				.registerTypeAdapter(Certificate.class,
						new CertificateAdapter())
				.registerTypeAdapter(Constants.Operation.class,
						new ConstantsAdapter(Constants.Operation.class))
				.registerTypeAdapter(
						listRegistrationRequests.getType(),
						new ListAdapter(listRegistrationRequests,
								new TypeToken<RegistrationRequest>() {
								}))
//				.registerTypeAdapter(
//						listDeviceSupportResponses.getType(),
//						new ListAdapter(listDeviceSupportResponses,
//								new TypeToken<DeviceSupportResponse>() {
//								}))
				.registerTypeAdapter(
						listRegistrationResponses.getType(),
						new ListAdapter(listRegistrationResponses,
								new TypeToken<RegistrationResponse>() {
								}))
				.registerTypeAdapter(
						listAuthenticationAssertions.getType(),
						new ListAdapter(listAuthenticationAssertions,
								new TypeToken<AuthenticationAssertion>() {
								}))
				.registerTypeAdapter(
						listRegistrationAssertions.getType(),
						new ListAdapter(listRegistrationAssertions,
								new TypeToken<RegistrationAssertion>() {
								}))
				.registerTypeAdapter(
						listAuthenticators.getType(),
						new ListAdapter(listAuthenticators,
								new TypeToken<Authenticator>() {
								}))
				.registerTypeAdapter(listFacets.getType(),
						new ListAdapter(listFacets, new TypeToken<FacetID>() {
						}))
				.registerTypeAdapter(
						listExtensions.getType(),
						new ListAdapter(listExtensions,
								new TypeToken<Extension>() {
								}))
				.registerTypeAdapter(listPolicies.getType(),
						new ListAdapter(listPolicies, new TypeToken<Policy>() {
						}))
				.registerTypeAdapter(
						listCriteria.getType(),
						new ListAdapter(listCriteria,
								new TypeToken<MatchCriteria>() {
								}))
				.registerTypeAdapter(
						listWhiteList.getType(),
						new ListAdapter(listWhiteList,
								new TypeToken<WhiteList>(){
								}))
				// .registerTypeAdapter(listRegReqs.getType(),
				// new ListAdapter(listRegReqs, new TypeToken<RegContext>() {
				// }))
				// .registerTypeAdapter(listAuthReqs.getType(),
				// new ListAdapter(listAuthReqs, new TypeToken() {
				// }))
				// .registerTypeAdapter(listDeregReqs.getType(),
				// new ListAdapter(listDeregReqs, new TypeToken() {
				// }))
				.registerTypeAdapter(
						listAuthenticatorAttachment.getType(),
						new ListAdapter(listAuthenticatorAttachment,
								new TypeToken<AuthenticatorAttachment>(){
								}))
				.registerTypeAdapter(
						fcParams.getType(),
						new Base64URLEncodedAdapter(
								new TypeToken<Base64URLEncoded>() {
								}))
				.registerTypeAdapter(
						b64PngInfo.getType(),
						new Base64URLEncodedAdapter(
								new TypeToken<List<PNGCharacteristics>>() {
								}));
	}

	static {
		try {
			INSTANCE = new UAFSchemaBuilder();
			CERT_INSTANCE = new UAFSchemaBuilder("cert");
		} catch (InvalidUAFMessageException e) {
			throw new UAFRuntimeException(
					"Error initializing UAF schema builder", e);
		}
	}
}
